#include <a_samp>
#include <myfuncs>
#include <file>
#include <string>
#include <core>

#include ideparse

#include dev/vehicles
#include dev/carmods

#pragma dynamic 1000000

#define INT_SIZE cellbits

new lod_stack[25000];





stock ParseLODModels2(const prefix[], const filename[], const destname[])
{
	new File:fp;

	for(new i =0 ; i<25000; i++)
		lod_stack[i] = 0;


	fp = fopen(filename, filemode:io_read);
	if(!fp) return 0;

	new line[256];

	print(" loading files into memory..");
	while(fread(fp, line, sizeof(line), false) > 0)
	{
		if(line[0] == '#')
			continue;

		line[strrchr(line, '\r')] = EOS;
		if(line[0] == EOS) continue;

		format(line, sizeof(line), "%s/%s", prefix, line);

		if(fexist(line))
		{
			printf("parsing %s...", line);
			ParseLODModelsInFile2(line);
		}

	}
	fclose(fp);


	print(" making table...");


	new File:fp2 = fopen(destname, filemode:io_write);

	/*
	new omin = 0, omax = 0, offset = 0;
	new maxobj = 0;
*/
	for(new i = 0; i < 25000; i++)
	{
		if(lod_stack[i])
		{
			format(line, sizeof(line), "%d, %d, \n", i, lod_stack[i]);
			fwrite(fp2, line);
		}
	}
	fclose(fp2);


	return 1;

}

stock ParseLODModelsInFile2(const filename[])
{
	new File:fp;

	fp = fopen(filename, filemode:io_read);
	if(!fp) return 0;

	new line[256], oid, oid2;
	new tmp[64], idx;

	while(fread(fp, line, sizeof(line), false) > 0)
	{
		//idx = 0;
		if(line[0] == '#' || line[0] == '\r')
			continue;

		idx = token_by_delim(line, tmp, ',', 0);

		if(idx == -1)
			continue;
		oid = strval(tmp);
		if(oid < 1)
			continue;

		idx = token_by_delim(line, tmp, ',', idx + 1);
		if(idx == -1)
			continue;
		if(tolower(tmp[0]) == 'l' && tolower(tmp[1]) == 'o' && tolower(tmp[2]) == 'd')
			continue; // lod object found
//		printf("reading line %s", line);

		tmp[0] = 'L';
		tmp[1] = 'O';
		tmp[2] = 'D';
		if((oid2 = FindObjectModelIDInFile(filename, tmp)) != 0)
		{
			lod_stack[oid] = oid2;
			/*format(line, sizeof(line), "%d, %d, # %s\n", oid, oid2, tmp);
			//print(line);
			fwrite(fp2, line);*/
		}


	}
	fclose(fp);

	return 0;
}



new objects_stack[30000/INT_SIZE+1];

stock ParseIDE2(const prefix[], const filename[], const name2[])
{
	new File:fp;

	fp = fopen(filename, filemode:io_read);
	if(!fp) return 0;

	for(new i = 0; i < 30000/INT_SIZE+1; i++)
		objects_stack[i] = 0;

	new line[256];

	print("reading files into memory....");
	while(fread(fp, line, sizeof(line), false) > 0)
	{
		if(line[0] == '#')
			continue;

		format(line, sizeof(line), "%s/%s", prefix, line);

		line[strrchr(line, '\r')] = EOS;
		if(fexist(line))
		{
			printf("parsing %s...", line);
			if(!ParseIDEFile2(line))
				print("file not found");
		}

	}
	fclose(fp);

	print("making table...");

	new File:fp2 = fopen(name2, filemode:io_write);

	new omin = 0, omax = 0;
	new maxobj = 0;

	for(new i = 1; i < 30000; i++)
	{
		if(getbool(objects_stack, i))
			if( i > maxobj) maxobj = i;
	}

	format(line, sizeof(line), "!%d\n", maxobj);
	fwrite(fp2, line);
	for(new i = 1; i < 30000; i++)
	{
		if(getbool(objects_stack, i))
		{
			if( i > maxobj) maxobj = i;
			if(!omin)
			{
				omin = i;
			}
			else
				omax = i;
		}
		else if(omin)
		{
			if(!omax) omax = omin;
			//printf("%d - %d", omin, omax);
			format(line, sizeof(line), "%d, %d, \n", omin, omax);
			fwrite(fp2, line);
			omin = 0;
			omax = 0;
		}
	}
	fclose(fp2);

	printf("!%d", maxobj);
	return 1;

}

stock ParseIDEFile2(filename[])
{
	new File:fp;

	fp = fopen(filename, filemode:io_read);

	if(!fp) return 0;

	new line[256], oid;
	new tmp[64];
	new idx;

	while(fread(fp, line, sizeof(line), false) > 0)
	{
		//idx = 0;

		idx = token_by_delim(line, tmp, ',', 0);
		if(idx == -1) continue;

		oid = strval(tmp);
		if(oid < 1) continue;
		else
			setbool(objects_stack, oid, true);
	}
	fclose(fp);

	return 1;
}

stock ParseIDE(const prefix[], const filename[])
{
	new File:fp;

	fp = fopen(filename, filemode:io_read);
	if(!fp) return 0;

	new line[256];

	while(fread(fp, line, sizeof(line), false) > 0)
	{
		if(line[0] == '#')
			continue;

		format(line, sizeof(line), "%s/%s", prefix, line);

		line[strrchr(line, '\r')] = EOS;
		if(fexist(line))
		{
			printf("parsing %s...", line);
			ParseIDEFile(line);
		}

	}
	fclose(fp);

	return 1;

}

stock ParseIDEFile(filename[])
{
	new File:fp, File:fp2;

	fp = fopen(filename, filemode:io_read);
	format(filename, 256, "done/%s", filename);
	if(!fp) return print("read fail!");
	fp2 = fopen(filename, filemode:io_write);
	if(!fp2) return print("write fail!");

	//if(!fp || !fp2) return 0;

	new line[256], oid,
		modelname[64],
		texturename[64],
		Float:dist;
	new tmp[64];
	new idx;

	while(fread(fp, line, sizeof(line), false) > 0)
	{
		//idx = 0;

		idx = token_by_delim(line, tmp, ',', 0);

		if(idx == -1)
		{
			fwrite(fp2, line);
			continue;
		}
		oid = strval(tmp);
		if(oid < 1)
		{
			fwrite(fp2, line);
			continue;
		}

		idx = token_by_delim(line, modelname, ',', idx + 1);
		if(idx == -1)
		{
			fwrite(fp2, line);
			continue;
		}
		idx = token_by_delim(line, texturename, ',', idx + 1);
		if(idx == -1)
		{
			fwrite(fp2, line);
			continue;
		}
		idx = token_by_delim(line, tmp, ',', idx + 1);
		if(idx == -1)
		{
			fwrite(fp2, line);
			continue;
		}
		dist = floatstr(tmp);

		idx = token_by_delim(line, tmp, ',', idx + 1);
		//flags = strval(tmp);
		if(idx != -1)
		{
			//printf("error %s", line);
			fwrite(fp2, line);
			continue;
		}

		#define FACTOR 2.5

		// config
		dist = dist / FACTOR;


		if(dist < 50.0)
			dist *= FACTOR;
		else if(dist > 450.0)
			dist /= FACTOR;

		if(strfind(modelname, "les") != -1)
			dist /= FACTOR;
		else if(strcmp(modelname, "LOD", true, 3) == 0)
			dist *= (FACTOR - 0.5);

		format(line, sizeof(line), "%d, %s, %s, %0.1f, %s", oid, modelname, texturename, dist, tmp);
		//print(line);
		fwrite(fp2, line);

	}
	fclose(fp);
	fclose(fp2);

	return 0;
}


stock ParseLODModels(const prefix[], const filename[], const destname[])
{
	new File:fp;


	fp = fopen(filename, filemode:io_read);
	if(!fp) return 0;
	new File:fp2 = fopen(destname, filemode:io_write);

	new line[256];

	while(fread(fp, line, sizeof(line), false) > 0)
	{
		if(line[0] == '#')
			continue;

		format(line, sizeof(line), "%s/%s", prefix, line);

		line[strrchr(line, '\r')] = EOS;
		if(fexist(line))
		{
			printf("parsing %s...", line);
			ParseLODModelsInFile(line, fp2);
		}

	}
	fclose(fp);
	fclose(fp2);

	return 1;

}

stock ParseLODModelsInFile(const filename[], File:fp2)
{
	new File:fp;

	fp = fopen(filename, filemode:io_read);
	if(!fp) return 0;

	new line[256], oid, oid2;
	new tmp[64], idx;

	while(fread(fp, line, sizeof(line), false) > 0)
	{
		//idx = 0;
		if(line[0] == '#' || line[0] == '\r')
			continue;

		idx = token_by_delim(line, tmp, ',', 0);

		if(idx == -1)
			continue;
		oid = strval(tmp);
		if(oid < 1)
			continue;

		idx = token_by_delim(line, tmp, ',', idx + 1);
		if(idx == -1)
			continue;
		if(tolower(tmp[0]) == 'l' && tolower(tmp[1]) == 'o' && tolower(tmp[2]) == 'd')
			continue; // lod object found
//		printf("reading line %s", line);

		tmp[0] = 'L';
		tmp[1] = 'O';
		tmp[2] = 'D';
		if((oid2 = FindObjectModelIDInFile(filename, tmp)) != 0)
		{
			format(line, sizeof(line), "%d, %d, # %s\n", oid, oid2, tmp);
			//print(line);
			fwrite(fp2, line);
		}


	}
	fclose(fp);

	return 0;
}
/*
stock ParseLODModel(const listname[], modelid)
{
	new File:fp;

	fp = fopen(listname, filemode:io_read);
	if(!fp) return modelid;

	new line[256], oid = 0;
	new tmp[64];
	new tmp2 = strrchr(listname, '/');
	new listpath[64];
	if(tmp2 != -1)
		strmid(listpath, listname, 0, tmp2);

	while(fread(fp, line, sizeof(line), false) > 0)
	{
		if(line[0] == '#')
			continue;

		if(tmp2 != -1)
		{
			format(line, sizeof(line), "%s/%s", listpath, line);
			line[strrchr(line, '\r')] = EOS;
			//print(line);
		}

		if(fexist(line))
		{
			if(FindObjectModelNameInFile(line, modelid, tmp) != 0)
			{
				fclose(fp);
				//printf("found %s in %s for %d", tmp, line, modelid);
				tmp[0] = 'L';
				tmp[1] = 'O';
				tmp[2] = 'D';

				if((oid = FindObjectModelIDInFile(line, tmp)) != 0)
				{
					format(line, sizeof(line), "%d, %d, # %s\n", modelid, oid, tmp);
					print(line);
					new File:fp2 = fopen("lod.dat", filemode:io_append);
					fwrite(fp2, line);
					fclose(fp2);
				}

				return modelid;
			}
		}

	}
	fclose(fp);

	return 0;

}*/
stock LoadCarModsFile(const filename[], const towrite[])
{
	new File:file_ptr, File:fp2;
	new line[256];
	new var_from_line[64];

	new modelname[64];
	new compid;

	new index;
	new vehicles_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	if(!file_ptr) return false;

	fp2 = fopen(towrite,filemode:io_write);
	if(!fp2) return false;

	vehicles_loaded = 0;

	//fwrite(fp2, "static stock const vmods[][][] = \n{\n");

	while(fread(file_ptr,line,256) > 0)
	{
	    index = 0;

		if(line[0] == '#') continue;


  		index = token_by_delim(line,modelname,',',index);
  		if(index == (-1)) continue;

		new i = 0;
		while(index != (-1))
		{

			index = token_by_delim(line, var_from_line, ',',index+1);
			if(index == (-1)) break;
			if(isnull(var_from_line)) break;
			if(var_from_line[0] == ' ')
				format(var_from_line, 64, "%s", var_from_line[1]);
			if(var_from_line[0] == '\t')
				format(var_from_line, 64, "%s", var_from_line[1]);
			compid = GetComponentID(var_from_line);
			if(!compid) printf("not found component for %s", var_from_line);
			else
			{
				format(var_from_line, 256, "\t/*%s*/ \ttuneinfo[%3d][%2d] = %d; \t// %s\n",
					modelname, GetVehicleID(modelname)-400, i, compid, var_from_line);
				fwrite(fp2, var_from_line);
				i++;
				//format(var_from_line, sizeof(var_from_line), "\t/*%s*/ \ttuneinfo[%d][i] = ", modelname, GetVehicleID(modelname)-400);
				//fwrite(fp2, var_from_line);
			}

		}

		//fwrite(fp2, "0 };\n");

		vehicles_loaded++;
	}

	//fwrite(fp2, "\n};\n");

	fclose(file_ptr);
	fclose(fp2);

	printf("Loaded %d vehicles from %s",vehicles_loaded,filename);
	return vehicles_loaded;

}

stock LoadCarColorsFile(const filename[], const towrite[])
{
	new File:file_ptr, File:fp2;
	new line[256];
	new var_from_line[64];

	new modelname[64], modelid;

	new index, tmpindex;
	new vehicles_loaded, maxi = 0;

	file_ptr = fopen(filename,filemode:io_read);
	if(!file_ptr) return false;

	fp2 = fopen(towrite,filemode:io_write);
	if(!fp2) return false;

	vehicles_loaded = 0;

	//fwrite(fp2, "static stock const vmods[][][] = \n{\n");

	while(fread(file_ptr,line,256) > 0)
	{
	    index = 0;

		if(line[0] == '#') continue;


  		index = token_by_delim(line,modelname,',',index);
  		if(index == (-1)) continue;
		modelid = GetVehicleID(modelname);

		if(modelid < 400) continue;

		format(var_from_line, sizeof(var_from_line), "%03d: ", modelid);
		fwrite(fp2, var_from_line);

		new i=0;
		while(index != (-1))
		{

			tmpindex = token_by_delim(line, var_from_line, ',',index+1);
			if(tmpindex == (-1))
			{
				index = token_by_delim(line, var_from_line, EOS, index+1);
			}
			else
				index = tmpindex;
			/*
			if(var_from_line[0] == ' ')
				format(var_from_line, 64, "%s", var_from_line[1]);
			if(var_from_line[0] == '\t')
				format(var_from_line, 64, "%s", var_from_line[1]);
			*/
			new len = strlen(var_from_line)-2;
			if(len > 0 && (var_from_line[len] == '\n' || var_from_line[len] == '\r'))
				var_from_line[len] = EOS;


			format(var_from_line, sizeof(var_from_line), "%s, ", var_from_line);
			fwrite(fp2, var_from_line);
			if(tmpindex == (-1))
				index = -1;
			i++;

		}

		//printf("%d", i);
		if(i > maxi) maxi = i;

		format(line, sizeof(line), "# %d; %s\n", i, modelname);
		fwrite(fp2, line);

		//fwrite(fp2, "0 };\n");

		vehicles_loaded++;
	}

	printf("%d", maxi);
	//fwrite(fp2, "\n};\n");

	fclose(file_ptr);
	fclose(fp2);

	printf("Loaded %d vehicles from %s",vehicles_loaded,filename);
	return vehicles_loaded;
}



/*
stock LoadVehiclesFile(const filename[], const towrite[])
{
	new File:file_ptr, File:fp2;
	new line[256];
	new var_from_line[64];

	new modelid;

	new index;
	new vehicles_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	if(!file_ptr) return false;

	fp2 = fopen(towrite,filemode:io_write);
	if(!fp2) return false;

	vehicles_loaded = 0;

	fwrite(fp2, "static stock const vnames[][] = \n{\n");

	while(fread(file_ptr,line,256) > 0)
	{
	    index = 0;

	    // Read type
  		index = token_by_delim(line,var_from_line,',',index);
  		if(index == (-1)) continue;
  		modelid = strval(var_from_line);
   		if(modelid < 400 || modelid > 612) continue;

  		index = token_by_delim(line,var_from_line,',',index+1);
  		if(index == (-1)) continue;

		if(var_from_line[0] == ' ')
			format(var_from_line, 64, "%s", var_from_line[1]);
		if(var_from_line[0] == '\t')
			format(var_from_line, 64, "%s", var_from_line[1]);


		format(line, 256, "\t\"%s\", // %d\n", var_from_line, modelid);
		fwrite(fp2, line);

		vehicles_loaded++;
	}

	fwrite(fp2, "\n};\n");

	fclose(file_ptr);
	fclose(fp2);

	printf("Loaded %d vehicles from %s",vehicles_loaded,filename);
	return vehicles_loaded;
}



public OnFilterScriptInit()
{
	LoadVehiclesFile("vehicles.ide", "vehicles.inc");
}
*/

static stock token_by_delim(const string[], return_str[], delim, start_index)
{
	new x=0;
	while(string[start_index] == ' ' || string[start_index] == '\t')
		start_index++;
	while(string[start_index] != EOS && string[start_index] != delim && string[start_index] != '#')
	{
		return_str[x] = string[start_index];
		x++;
		start_index++;
	}
	return_str[x] = EOS;
	if(string[start_index] == EOS) start_index = (-1);
	return start_index;
}


static stock setbool(arr[], idx, bool:val) // set boolean for packed booleans type
{
	if(val)
		arr[idx / INT_SIZE] |= 1 << (idx % INT_SIZE);
	else
		arr[idx / INT_SIZE] &= ~(1 << (idx % INT_SIZE));
	return(arr[idx / INT_SIZE]);
}

static stock getbool(arr[], idx) // get boolean for packed booleans type
{
	return (arr[idx / INT_SIZE] >> (idx % INT_SIZE)) & 1;
}


public OnFilterScriptInit()
{
	printf("%d", heapspace());
	/*
	LoadCarModsFile("carmods.dat", "vmods.inc");
	*/
	/*
	ParseIDE2("data/maps_u", "data/maps_u/list.lst", "data/objects_u.dat");
	ParseIDE2("data/maps_a", "data/maps_a/list.lst", "data/objects_a.dat");
	ParseIDE2("data/maps_g", "data/maps_g/list.lst", "data/objects_g.dat");
	ParseIDE2("data/maps_ov", "data/maps_ov/list.lst", "data/objects_ov.dat");
	ParseLODModels("data/maps_u", "data/maps_u/list.lst", "data/lod_u.dat");
	ParseLODModels("data/maps_a", "data/maps_a/list.lst", "data/lod_a.dat");
	ParseLODModels("data/maps_g", "data/maps_g/list.lst", "data/lod_g.dat");
	ParseLODModels("data/maps_cr", "data/maps_cr/list.lst", "data/lod_cr.dat");
	ParseLODModels("data/maps_ov", "data/maps_ov/list.lst", "data/lod_ov.dat");

	ParseLODModels2("data/maps_u", "data/maps_u/list.lst", "data/lod2_u.dat");
	ParseLODModels2("data/maps_a", "data/maps_a/list.lst", "data/lod2_a.dat");
	ParseLODModels2("data/maps_g", "data/maps_g/list.lst", "data/lod2_g.dat");
	ParseLODModels2("data/maps_cr", "data/maps_cr/list.lst", "data/lod2_cr.dat");
	ParseLODModels2("data/maps_ov", "data/maps_ov/list.lst", "data/lod2_ov.dat");
	*/
	//LoadCarModsFile("carmods.dat", "vmods.inc");
	ParseIDE("data/maps_cr", "data/maps_cr/list.lst");
	/*
	LoadCarColorsFile("carcols.dat", "carcolors.dat");
	ParseIDE2("data/maps_sa", "data/maps_sa/list.lst", "data/objects_sa.dat");
	ParseLODModels2("data/maps_sa", "data/maps_sa/list.lst", "data/lod2_sa.dat");
	*/
	//print("parsing done, unloading...");
	//ndRconCommand("unloadfs parsegta");
	//SetTimer("unload", 1000, 0);
	return 1;
}





forward unload();

public unload()
{
	SendRconCommand("unloadfs parsegta");
}



